#include "InputDevice.h"
#define MOUSE_BUFFER_SIZE 16
namespace SLG
{
	extern FILE* fp;
	InputDevice::InputDevice(void)
	{
	}

	InputDevice::~InputDevice(void)
	{
	}

	HRESULT InputDevice::Init(HWND hWnd)
	{
		HRESULT hr;
		if( FAILED( hr = DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION,
			IID_IDirectInput8, ( void** )&m_input, NULL ) ) )
			return hr;

		if(FAILED(hr=m_mouse.Init(hWnd,m_input)))
		{
			return hr;
		}

		if(FAILED(hr=m_keyboard.Init(hWnd,m_input)))
		{
			return hr;
		}

		return S_OK;
	}

	void InputDevice::GetState()
	{
		m_mouse.GetState();
		m_keyboard.GetState();
	}

	Mouse::Mouse()
		:m_LeftButtonProc(NULL),
		m_RightButtonProc(NULL)
	{
		m_mousePointX=0;
		m_mousePointY=0;
	}
	
	D3DXVECTOR2 InputDevice::GetPoint()
	{
		return m_mouse.GetPoint();
	}

	bool InputDevice::SetProc(INPUT_STR is,boost::function<void()>func)
	{
		if(is.device==MOUSE)
		{
			m_mouse.SetMouseProc(is.key,is.state,func);
		}
		else if(is.device==KEYBOARD)
		{
			m_keyboard.SetKeyBoardProc(is.key,func);
		}
		else
		{
			return false;
		}
		return true;
	}

	Mouse::~Mouse()
	{
	}

	void Mouse::SetMouseProc(int button,int state,boost::function<void()> func)
	{
		switch(button)
		{
		case LButton:
			if(state==Press)
				SetLeftButtonProc(func);
			break;
		case MButton:
			break;
		case RButton:
			if(state==Press)
				SetRightButtonProc(func);
			break;
		}
	}

	D3DXVECTOR2 Mouse::GetPoint()
	{
		return D3DXVECTOR2(m_mousePointX,m_mousePointY);
	}

	void Mouse::SetLeftButtonProc(boost::function<void()> func)
	{
		m_LeftButtonProc=func;
	}

	void Mouse::SetRightButtonProc(boost::function<void()> func)
	{
		m_RightButtonProc=func;
	}

	HRESULT Mouse::Init(HWND hWnd,LPDIRECTINPUT8 input)
	{
		HRESULT hr;
		if(FAILED(hr=input->CreateDevice(GUID_SysMouse,&m_mouseDevice,NULL)))
		{
			return hr;
		}

		if(FAILED(hr=m_mouseDevice->SetDataFormat(&c_dfDIMouse)))
		{
			return hr;
		}

		if(FAILED(hr=m_mouseDevice->SetCooperativeLevel(hWnd,DISCL_FOREGROUND|DISCL_EXCLUSIVE)))
		{
			return hr;
		}

		DIPROPDWORD dipdw;

		dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
		dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
		dipdw.diph.dwObj        = 0;
		dipdw.diph.dwHow        = DIPH_DEVICE;
		dipdw.dwData            = MOUSE_BUFFER_SIZE;

		if (FAILED (hr = m_mouseDevice->SetProperty (DIPROP_BUFFERSIZE, &dipdw.diph)))
		{
			return false; //... can't set buffered device data for keyboard device
		}

		hr=m_mouseDevice->Acquire();
		return S_OK;
	}



	void Mouse::GetState()
	{

		static DIDEVICEOBJECTDATA mousebuf [MOUSE_BUFFER_SIZE];
		DWORD                     mElements;

		mElements = MOUSE_BUFFER_SIZE;
		HRESULT hr;
		hr = m_mouseDevice->GetDeviceData (sizeof(DIDEVICEOBJECTDATA), mousebuf, &mElements, 0);
		if (hr != DI_OK) 
		{
			if (hr == DI_BUFFEROVERFLOW)
				; //... mouse buffer overflow
			else
				mElements = 0;
			hr = m_mouseDevice->Acquire();
			while (hr == DIERR_INPUTLOST) 
				hr = m_mouseDevice->Acquire();
		}

		for(DWORD i=0;i<mElements;i++)
		{
			switch(mousebuf[i].dwOfs)
			{
			case DIMOFS_BUTTON0:
				m_mouseLeftButton = (mousebuf[i].dwData&0x80) ? true : false;
				if(MouseLeftClicked())
				{
					if(m_LeftButtonProc!=NULL)
					{
						m_LeftButtonProc();
					}
				}
				break;
			case DIMOFS_BUTTON1:
				m_mouseRightButton = (mousebuf[i].dwData&0x80) ? true : false;
				if(MouseRightClicked())
				{
					if(m_RightButtonProc!=NULL)
					{
						m_RightButtonProc();
					}
				}
				break;
			case DIMOFS_BUTTON2:
				break;
			case DIMOFS_X:
				m_mousePointX+=mousebuf[i].dwData;
				break;
			case DIMOFS_Y:
				m_mousePointY+=mousebuf[i].dwData;
				break;
			case DIMOFS_Z:
				break;
			}
		}
	}

	bool Mouse::MouseLeftClicked()
	{
		static bool bPressed=false;
		if(m_mouseLeftButton)
			bPressed=true;
		if(bPressed)
		{
			if(!m_mouseLeftButton)
			{
				bPressed=false;
				return TRUE;
			}
		}
		return FALSE;
	}

	bool Mouse::MouseRightClicked()
	{
		static bool bPressed=false;
		if(m_mouseRightButton)
			bPressed=true;
		if(bPressed)
		{
			if(!m_mouseRightButton)
			{
				bPressed=false;
				return TRUE;
			}
		}
		return FALSE;
	}

	KeyBoard::KeyBoard()
	{
		memset(m_key,0,132);
	}

	HRESULT KeyBoard::Init(HWND hWnd,LPDIRECTINPUT8 input)
	{
		for(int i=0;i<132;i++)
		{
			m_KeyBoardProc[i]=NULL;
		}
		HRESULT hr;
		if(FAILED(hr=input->CreateDevice(GUID_SysKeyboard,&m_keyboardDevice,NULL)))
		{
			return hr;
		}

		if(FAILED(hr=m_keyboardDevice->SetDataFormat(&c_dfDIKeyboard)))
		{
			return hr;
		}
		DWORD flags=DISCL_FOREGROUND|DISCL_EXCLUSIVE;
		if(FAILED(hr=m_keyboardDevice->SetCooperativeLevel(hWnd,flags)))
		{
			return hr;
		}

		DIPROPDWORD dipdw;

		dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
		dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
		dipdw.diph.dwObj        = 0;
		dipdw.diph.dwHow        = DIPH_DEVICE;
		dipdw.dwData            = MOUSE_BUFFER_SIZE;

		if (FAILED (hr = m_keyboardDevice->SetProperty (DIPROP_BUFFERSIZE, &dipdw.diph)))
		{
			return hr; //... can't set buffered device data for keyboard device
		}

		hr=m_keyboardDevice->Acquire();
		return S_OK;
	}

	void KeyBoard::GetState()
	{
		static DIDEVICEOBJECTDATA keyboardbuf [MOUSE_BUFFER_SIZE];
		DWORD                     mElements;

		mElements = MOUSE_BUFFER_SIZE;
		HRESULT hr;
		hr = m_keyboardDevice->GetDeviceData (sizeof(DIDEVICEOBJECTDATA), keyboardbuf, &mElements, 0);
		if (hr != DI_OK) 
		{
			if (hr == DI_BUFFEROVERFLOW)
				; //... mouse buffer overflow
			else
				mElements = 0;
			hr = m_keyboardDevice->Acquire();
			while (hr == DIERR_INPUTLOST) 
				hr = m_keyboardDevice->Acquire();
		}

		for(DWORD i=0;i<mElements;i++)
		{
			KeyType key;
			switch(keyboardbuf[i].dwOfs)
			{
			case DIK_ESCAPE       : key = KeyEscape	; break;
			case DIK_1            : key = Key1		; break;
			case DIK_2            : key = Key2		; break;
			case DIK_3            : key = Key3		; break;
			case DIK_4            : key = Key4		; break;
			case DIK_5            : key = Key5		; break;
			case DIK_6            : key = Key6            ; break;
			case DIK_7            : key = Key7            ; break;
			case DIK_8            : key = Key8            ; break;
			case DIK_9            : key = Key9            ; break;
			case DIK_0            : key = Key0            ; break;
			case DIK_MINUS        : key = KeyMinus        ; break;
			case DIK_EQUALS       : key = KeyEquals       ; break;
			case DIK_BACK         : key = KeyBack         ; break;
			case DIK_TAB          : key = KeyTab          ; break;
			case DIK_Q            : key = KeyQ            ; break;
			case DIK_W            : key = KeyW            ; break;
			case DIK_E            : key = KeyE            ; break;
			case DIK_R            : key = KeyR            ; break;
			case DIK_T            : key = KeyT            ; break;
			case DIK_Y            : key = KeyY            ; break;
			case DIK_U            : key = KeyU            ; break;
			case DIK_I            : key = KeyI            ; break;
			case DIK_O            : key = KeyO            ; break;
			case DIK_P            : key = KeyP            ; break;
			case DIK_LBRACKET     : key = KeyLBracket     ; break;
			case DIK_RBRACKET     : key = KeyRBracket     ; break;
			case DIK_RETURN       : key = KeyReturn       ; break;
			case DIK_LCONTROL     : key = KeyLControl     ; break;
			case DIK_A            : key = KeyA            ; break;
			case DIK_S            : key = KeyS            ; break;
			case DIK_D            : key = KeyD            ; break;
			case DIK_F            : key = KeyF            ; break;
			case DIK_G            : key = KeyG            ; break;
			case DIK_H            : key = KeyH            ; break;
			case DIK_J            : key = KeyJ            ; break;
			case DIK_K            : key = KeyK            ; break;
			case DIK_L            : key = KeyL            ; break;
			case DIK_SEMICOLON    : key = KeySemicolon    ; break;
			case DIK_APOSTROPHE   : key = KeyApostrophe   ; break;
			case DIK_GRAVE        : key = KeyGrave        ; break;
			case DIK_LSHIFT       : key = KeyLShift       ; break;
			case DIK_BACKSLASH    : key = KeyBackSlash    ; break;
			case DIK_Z            : key = KeyZ            ; break;
			case DIK_X            : key = KeyX            ; break;
			case DIK_C            : key = KeyC            ; break;
			case DIK_V            : key = KeyV            ; break;
			case DIK_B            : key = KeyB            ; break;
			case DIK_N            : key = KeyN            ; break;
			case DIK_M            : key = KeyM            ; break;
			case DIK_COMMA        : key = KeyComma        ; break;
			case DIK_PERIOD       : key = KeyPeriod       ; break;
			case DIK_SLASH        : key = KeySlash        ; break;
			case DIK_RSHIFT       : key = KeyRShift       ; break;
			case DIK_MULTIPLY     : key = KeyMultiply     ; break;
			case DIK_LMENU        : key = KeyLMenu        ; break;
			case DIK_SPACE        : key = KeySpace        ; break;
			case DIK_CAPITAL      : key = KeyCapital      ; break;
			case DIK_F1           : key = KeyF1           ; break;
			case DIK_F2           : key = KeyF2           ; break;
			case DIK_F3           : key = KeyF3           ; break;
			case DIK_F4           : key = KeyF4           ; break;
			case DIK_F5           : key = KeyF5           ; break;
			case DIK_F6           : key = KeyF6           ; break;
			case DIK_F7           : key = KeyF7           ; break;
			case DIK_F8           : key = KeyF8           ; break;
			case DIK_F9           : key = KeyF9           ; break;
			case DIK_F10          : key = KeyF10          ; break;
			case DIK_NUMLOCK      : key = KeyNumLock      ; break;
			case DIK_SCROLL       : key = KeyScroll       ; break;
			case DIK_NUMPAD7      : key = KeyNumPad7      ; break;
			case DIK_NUMPAD8      : key = KeyNumPad8      ; break;
			case DIK_NUMPAD9      : key = KeyNumPad9      ; break;
			case DIK_SUBTRACT     : key = KeySubtract     ; break;
			case DIK_NUMPAD4      : key = KeyNumPad4      ; break;
			case DIK_NUMPAD5      : key = KeyNumPad5      ; break;
			case DIK_NUMPAD6      : key = KeyNumPad6      ; break;
			case DIK_ADD          : key = KeyAdd          ; break;
			case DIK_NUMPAD1      : key = KeyNumPad1      ; break;
			case DIK_NUMPAD2      : key = KeyNumPad2      ; break;
			case DIK_NUMPAD3      : key = KeyNumPad3      ; break;
			case DIK_NUMPAD0      : key = KeyNumPad0      ; break;
			case DIK_DECIMAL      : key = KeyDecimal      ; break;
			case DIK_OEM_102      : key = KeyOEM_102      ; break;
			case DIK_F11          : key = KeyF11          ; break;
			case DIK_F12          : key = KeyF12          ; break;
			case DIK_F13          : key = KeyF13          ; break;
			case DIK_F14          : key = KeyF14          ; break;
			case DIK_F15          : key = KeyF15          ; break;
			case DIK_KANA         : key = KeyKana         ; break;
			case DIK_ABNT_C1      : key = KeyABNT_C1      ; break;
			case DIK_CONVERT      : key = KeyConvert      ; break;
			case DIK_NOCONVERT    : key = KeyNoConvert    ; break;
			case DIK_YEN          : key = KeyYen          ; break;
			case DIK_ABNT_C2      : key = KeyABNT_C2      ; break;
			case DIK_NUMPADEQUALS : key = KeyNumPadEquals ; break;
			case DIK_PREVTRACK    : key = KeyPrevTrack    ; break;
			case DIK_AT           : key = KeyAt           ; break;
			case DIK_COLON        : key = KeyColon        ; break;
			case DIK_UNDERLINE    : key = KeyUnderLine    ; break;
			case DIK_KANJI        : key = KeyKANJI        ; break;
			case DIK_STOP         : key = KeyStop         ; break;
			case DIK_AX           : key = KeyAx           ; break;
			case DIK_UNLABELED    : key = KeyUnlabeled    ; break;
			case DIK_NEXTTRACK    : key = KeyNextTrack    ; break;
			case DIK_NUMPADENTER  : key = KeyNumPadEnter  ; break;
			case DIK_RCONTROL     : key = KeyRControl     ; break;
			case DIK_MUTE         : key = KeyMute         ; break;
			case DIK_CALCULATOR   : key = KeyCalculator   ; break;
			case DIK_PLAYPAUSE    : key = KeyPlayPause    ; break;
			case DIK_MEDIASTOP    : key = KeyMediaStop    ; break;
			case DIK_VOLUMEDOWN   : key = KeyVolumeDown   ; break;
			case DIK_VOLUMEUP     : key = KeyVolumeUp     ; break;
			case DIK_WEBHOME      : key = KeyWebHome      ; break;
			case DIK_NUMPADCOMMA  : key = KeyNumPadComma  ; break;
			case DIK_DIVIDE       : key = KeyDivide       ; break;
			case DIK_SYSRQ        : key = KeySysRQ        ; break;
			case DIK_RMENU        : key = KeyRMenu        ; break;
			case DIK_PAUSE        : key = KeyPause        ; break;
			case DIK_HOME         : key = KeyHome         ; break;
			case DIK_UP           : key = KeyUp           ; break;
			case DIK_PRIOR        : key = KeyPrior        ; break;
			case DIK_LEFT         : key = KeyLeft         ; break;
			case DIK_RIGHT        : key = KeyRight        ; break;
			case DIK_END          : key = KeyEnd          ; break;
			case DIK_DOWN         : key = KeyDown         ; break;
			case DIK_NEXT         : key = KeyNext         ; break;
			case DIK_INSERT       : key = KeyInsert       ; break;
			case DIK_DELETE       : key = KeyDelete       ; break;
			case DIK_LWIN         : key = KeyLWin         ; break;
			case DIK_RWIN         : key = KeyRWin         ; break;
			case DIK_APPS         : key = KeyApps         ; break;
			}
			m_key[key] = keyboardbuf[i].dwData & 0x80? true : false;
		}
		for(int i=0;i<132;i++)
		{
			if(m_key[i]==true&&m_KeyBoardProc[i]!=NULL)
			{
				m_KeyBoardProc[i]();
			}
		}
	}

	void KeyBoard::SetKeyBoardProc(int key,boost::function<void()> func)
	{
		m_KeyBoardProc[key]=func;
	}

	bool KeyBoard::GetKeyState(KeyType t)
	{
		return m_key[t];
	}

	KeyBoard::~KeyBoard()
	{
	}

}